package net.xinqushi.design.templateMethod.pool;

import net.xinqushi.design.templateMethod.core.DefaultSetting;
import net.xinqushi.design.templateMethod.util.NumberUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

public class SocketConnectionFactory implements PoolableConnectionFactory<Socket> {

	protected volatile InetSocketAddress address=null;

	protected volatile String username;

	protected volatile String password;

	protected int timeout=DefaultSetting.CONNECT_WAIT_TIME;
	
	protected int readTimeout=DefaultSetting.SOCKET_READ_TIMEOUT;

	public SocketConnectionFactory(String host,int port,String username,String password) throws IOException{
		address=new InetSocketAddress(host,port);
		this.username=username;
		this.password=password;
	}

	public Socket makeConnection() throws Exception {
		Socket socket=new Socket();
		socket.connect(address,timeout);
		socket.setSoTimeout(readTimeout);
		try{
			ByteArrayOutputStream write_buff=new ByteArrayOutputStream();
			byte[] bytes=("user:"+username).getBytes();
			write_buff.write(NumberUtils.convertIntegerToByteArray(bytes.length));
			write_buff.write(bytes);
			write_buff.writeTo(socket.getOutputStream());
			write_buff.close();
			byte[] read_buff=new byte[50*1024];
			int readBytes=0;
			while(true){
				if((readBytes=socket.getInputStream().read(read_buff))>0){
					break;
				}
			}
			write_buff=new ByteArrayOutputStream();
			write_buff.write(read_buff, 0, readBytes);
			if(!Boolean.parseBoolean(write_buff.toString())){
				destroyConnection(socket);
			}
		}catch(Exception e){
			destroyConnection(socket);
			e.printStackTrace();
		}
		return socket;
	}

	public void destroyConnection(Socket obj) throws Exception {
		try{
			if(obj!=null&&!obj.isClosed()){			
				obj.close();
			}
		}catch(Exception e){

		}finally{
			obj=null;
		}

	}

	public boolean validateConnection(Socket obj) {
		if(obj==null||obj.isClosed()){
			return false;
		}
		try{
			ByteArrayOutputStream write_buff=new ByteArrayOutputStream();
			byte[] bytes="1".getBytes();
			write_buff.write(NumberUtils.convertIntegerToByteArray(bytes.length));
			write_buff.write(bytes);
			write_buff.writeTo(obj.getOutputStream());
			write_buff.close();
			return true;
		}catch(Exception e){
			return false;
		}
	}

	public void activateConnection(Socket obj) throws Exception {
		destroyConnection(obj);
		obj=makeConnection();
		if(!validateConnection(obj)){
			throw new Exception("activate connection failed!");
		}
	}

	public void passivateConnection(Socket obj) throws Exception {

	}

}
